#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <cstring>
#include <arpa/inet.h>
#include <netinet/in.h>
#include "protocol.hpp"
#include <pthread.h>

using namespace std;

void* Run(void* arg)
{
  int sock=*(int*)arg;
  delete (int*)arg;

  while(true)
  {
    request rq;
    response rsp={0,0};

    int size=recv(sock,&rq,sizeof(rq),0);
    if(size>0)
    {
      switch(rq.op)
      {
        case '+':
           rsp.result = rq.x + rq.y;          break;
        case '-':
           rsp.result = rq.x - rq.y;                    break;
        case '*':
           rsp.result = rq.x * rq.y;         break;
        case '/':
                    if(rq.y == 0){
                        rsp.cond = 1; //除零
                    }
                    else{
                        rsp.result = rq.x / rq.y;
                    }
                    break;
        case '%':
                    if(rq.y == 0){
                        rsp.cond = 2; //除零
                    }
                    else{
                        rsp.result = rq.x / rq.y;
                    }
                    break;
        default:
                    rsp.cond = 3; //非法运算
                    break;
      }
      send(sock,&rsp,sizeof(rsp),0);
    }else if(sock==0)
    {
      cout<<" server quit"<<endl;
      break;
    }else
    break;
  }
  return nullptr;
}

int main(int argc,char* argv[])
{
  if(argc!=2)
  {
    cerr<<argv[0]<<" port"<<endl;
      exit(1);
  }

  int sockfd=socket(AF_INET,SOCK_STREAM,0);
  if(sockfd<0)
  {
    cerr<<"socket error"<<endl;
    exit(1);
  }

  struct sockaddr_in le;
  memset(&le,0,sizeof(le));
  le.sin_family=AF_INET;
  le.sin_port=htons(atoi(argv[1]));
  le.sin_addr.s_addr=0;
  socklen_t len=sizeof(le);
  if(bind(sockfd,(struct sockaddr*)&le,len)<0)
  {
    cerr<<"bind error"<<endl;
    exit(2);
  }

  if(listen(sockfd,5)<0)
  {
    cerr<<"listen error"<<endl;
    exit(3);
  }

  struct sockaddr_in peer;
  while(true)
  {
    socklen_t plen=sizeof(peer);
    int sock=accept(sockfd,(struct sockaddr*)&peer,&plen);
    if(sock<0)
    {
      cerr<<" accept error"<<endl;
      continue;
    }

    pthread_t tid;
    int *p=new int(sock);
    pthread_create(&tid,nullptr,Run,p);
  }
  return 0;
}
